home *** CD-ROM | disk | FTP | other *** search
/ Aminet 3 / Aminet 3 - July 1994.iso / Aminet / util / boot / BindNames2.lha / bindnames.c next >
Encoding:
C/C++ Source or Header  |  1994-06-01  |  12.8 KB  |  475 lines

  1. /* ====================================================================== */
  2.  
  3. /*    BindNames.c by Dave Haynie
  4.      Hacked by Dan Barrett to allow spaces in volume and path names.
  5.  
  6.     This is a simple utility to remove some of the drudgery of program
  7.     installation.  Instead of having to edit a Startup-Sequence for
  8.     every logical name that must be used by a new program, this lets
  9.     names be block-allocated.  The BindNames program looks for files
  10.     in the SYS:Names directory.  Each of these files contains any number
  11.     of lines of the form:
  12.     
  13.         Name:    Path
  14.     
  15.     Where "Name" is the logical name we're assigning, "Path" is the
  16.     path name we're making equivalent.  
  17. */
  18.  
  19. #define    VERSION        "2.0"
  20. static char version[] = "\0$VER: BindNames " VERSION " (01.06.94)";
  21. #define    HELLO        "BindNames V" VERSION " by Dave Haynie and Dan Barrett"
  22.  
  23. #include <exec/types.h>
  24. #include <exec/memory.h>    
  25. #include <libraries/dos.h>
  26. #include <libraries/dosextens.h>
  27. #ifdef AZTEC_C
  28. # include <functions.h>
  29. #else
  30. # include <all/protos.h>
  31. #endif
  32. #include <stdio.h>
  33. #include <ctype.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36.  
  37. /* ====================================================================== */
  38.  
  39. /* Macros */
  40.  
  41. #define CADDR(x)    ((BPTR)(((ULONG)x)>>2))
  42. #define NAMEDIR        "SYS:Names"
  43. #define    NAMEDIRVAR    "BindNamesDirectory"
  44. #define CopyStr(s)    strcpy(malloc(strlen(s)+1),s)
  45. #define FreeStr(s)    free(s)
  46.  
  47. /* The "-rr" option doesn't like NewList, bit it's real simple.  WHEN can
  48.    we have inline functions.... */
  49.  
  50. #define NewList(l)    { (l)->lh_Head     = (struct Node *)&(l)->lh_Tail; \
  51.               (l)->lh_TailPred = (struct Node *)&(l)->lh_Head; \
  52.               (l)->lh_Tail     = NULL;        \
  53.             }
  54.  
  55. /* ====================================================================== */
  56.  
  57. /* Global variables */
  58.  
  59. extern struct DosLibrary *DosBase = NULL;
  60. struct DosInfo *info = NULL;
  61. struct DeviceList *lastdev;
  62. BPTR namelock = NULL;
  63. BOOL verbose = FALSE;
  64. BOOL test = FALSE;
  65. BOOL oldBehavior = FALSE;
  66. struct FileInfoBlock *fileinfo = NULL;
  67.  
  68. /* ====================================================================== */
  69.  
  70. /* Return the name of the BindNames name directory. */
  71.  
  72. char *NameDir(void)
  73. {
  74.     char *dir;
  75.     static char default_dir[] = NAMEDIR;
  76.  
  77.     if (oldBehavior || ((dir = getenv(NAMEDIRVAR)) == NULL))
  78.         return(default_dir);
  79.     else
  80.         return(dir);
  81. }
  82.  
  83. /* ====================================================================== */
  84.  
  85. char Hello(void)
  86. {
  87.     printf("\2337m%s\2330m\n", HELLO);
  88.     printf("The current name directory is \"%s\"\n\n", NameDir());
  89. }
  90.  
  91. /* ====================================================================== */
  92.  
  93. /* This function makes a BCPL string into a C style string. */
  94.  
  95. char *b2cstr(char *cstr, BPTR bptr) {
  96.    char *ptr = (char *)BADDR(bptr);
  97.    strncpy(cstr,ptr+1,*ptr);
  98.    cstr[*ptr] = '\0';
  99.    return cstr;       
  100. }
  101.  
  102. /* This function allocates things in a DOS friendly way. */
  103.  
  104. void *DOSAlloc(LONG size) {
  105.    LONG *ptr = AllocMem(size+4,MEMF_PUBLIC|MEMF_CLEAR);
  106.    *ptr = size+4;
  107.    return ptr+1;
  108. }
  109.  
  110. /* This function frees memory in a DOS friendly way. */
  111.  
  112. void DOSFree(void *mem) {
  113.    LONG *ptr = (LONG *)mem;
  114.    FreeMem(ptr-1,*(ptr-1));
  115. }
  116.  
  117. /* ====================================================================== */
  118.  
  119. /* Here we manage name trees.  Name nodes are built from the device list
  120.    first.  All primary nodes based on the device list have NULL paths,
  121.    indicating that they are primary and thus, don't need to be recreated.
  122.    Subsequent nodes are added to the node that they depend on.  If a node 
  123.    is encountered that doesn't have a parent listed yet, it will be place
  124.    on a temporary node list. */
  125.  
  126. struct NameNode {
  127.    struct Node node;
  128.    struct NameNode *parent;
  129.    struct List children;
  130.    char *path;
  131. };
  132.  
  133. struct List Names;
  134. struct NameNode *lostnodes;
  135.  
  136. /* This function creates a name node, allocating whatever memory is 
  137.    needed. */
  138.  
  139. struct NameNode *MakeNode(char *name, char *path) {
  140.    struct NameNode *nn;
  141.    
  142.    if (!(nn = calloc(1,sizeof(struct NameNode)))) return NULL;
  143.    if (name) nn->node.ln_Name = CopyStr(name);
  144.    NewList(&nn->children);
  145.    if (path) nn->path = CopyStr(path);
  146.    return nn;
  147. }
  148.  
  149. /* This function finds a particular name in the Names data base, via a 
  150.    depth-first search.  If it finds the name, it returns that node, 
  151.    otherwise, it returns NULL. */
  152.  
  153. struct NameNode *FindNode(struct List *lst,char *name) {
  154.    struct Node *n;
  155.    struct NameNode *nn;
  156.    
  157.    for (n = lst->lh_Head; n->ln_Succ; n = n->ln_Succ) {
  158.       if (!(stricmp(name,n->ln_Name))) return (struct NameNode *)n;
  159.       if (nn = FindNode(&((struct NameNode *)n)->children,name)) return nn;
  160.    }
  161.    return NULL;
  162. }
  163.  
  164. /* This is the node assignment routine.  It accepts a node name and a path
  165.    for assignment.  It handles all the proper node creations to add that
  166.    information to the node data base. */
  167.    
  168. void DefNode(char *name, char *path) {
  169.    struct NameNode *nn, *parent;
  170.    char pardev[64];
  171.    int i;
  172.    
  173.    for (i = 0; path[i] != ':' && i < 63; ++i) pardev[i] = path[i];
  174.    pardev[i] = '\0';
  175.    if (!(parent = FindNode(&Names,pardev))) {
  176.       AddHead(&lostnodes->children,(struct Node *)(parent=MakeNode(pardev,NULL)));
  177.       parent->parent = lostnodes;
  178.    }
  179.    
  180.    if (!(nn = FindNode(&Names,name)))
  181.       nn = MakeNode(name,path);
  182.    else {
  183.       Remove((struct Node *)nn);
  184.       if (nn->path) FreeStr(nn->path);
  185.       nn->path = CopyStr(path);
  186.    }
  187.  
  188.    AddHead(&parent->children,(struct Node *)nn);
  189. }  
  190.  
  191.  
  192. /* Strip trailing spaces from a string. */
  193.  
  194. void StripTrailingSpace(char *str)
  195. {
  196.     char *p;
  197.     int len;
  198.  
  199.    /* Do nothing to NULL strings and empty strings. */
  200.  
  201.     if (!str)
  202.         return;
  203.  
  204.     len = strlen(str);
  205.     if (len == 0)
  206.         return;
  207.  
  208.    /* Point at last character before the NULL.  len is >= 1. */
  209.  
  210.     p = str + len - 1;
  211.  
  212.    /* Skip to the point ahead of all trailing space chars. */
  213.  
  214.     while ((p >= str) && (*p == ' '))
  215.         p--;
  216.  
  217.    /* Whomp it. */
  218.  
  219.     *(++p) = '\0';
  220. }
  221.  
  222.  
  223. /* This function reads in the individual file's data and builds entries
  224.    in the name list based on that data. */
  225.    
  226. void AddFIB(struct FileInfoBlock *fib,char *name) {  
  227.    BPTR file;
  228.    char *buf,*com,*path;
  229.       
  230.    if (buf = AllocMem(fib->fib_Size+1,0L)) {
  231.       if (file = Open(name,MODE_OLDFILE)) {
  232.          Read(file,buf,fib->fib_Size);
  233.          buf[fib->fib_Size] = '\0';
  234.          if (oldBehavior)
  235.          {
  236.              com = strtok(strupr(buf)," :\t\n");
  237.              path = strtok(NULL," \t\n");
  238.          }
  239.          else
  240.          {
  241.              com = strtok(buf,":\t\n");
  242.              path = strtok(NULL,"\t\n");
  243.              StripTrailingSpace(com);
  244.              StripTrailingSpace(path);
  245.          }
  246.          while (com && path) {
  247.             DefNode(com,path);
  248.             if (oldBehavior)
  249.             {
  250.                 com = strtok(NULL," :\t\n");
  251.                 path = strtok(NULL," \t\n");
  252.             }
  253.             else
  254.             {
  255.                 com = strtok(NULL,":\t\n");
  256.                 path = strtok(NULL,"\t\n");
  257.             StripTrailingSpace(com);
  258.                 StripTrailingSpace(path);
  259.             }
  260.          }
  261.          Close(file);
  262.       }
  263.       FreeMem(buf,fib->fib_Size+1);
  264.    }
  265. }
  266.  
  267. /* ====================================================================== */
  268.  
  269. /* This function opens up the stuff we need. */
  270.        
  271. BOOL DoInits(void) {
  272.    if (!(DosBase = (struct DosLibrary *)OpenLibrary("dos.library",33L)))
  273.       return FALSE;
  274.    if (!(info = (struct DosInfo *)BADDR(((struct RootNode *)DosBase->dl_Root)->rn_Info)))
  275.       return FALSE;
  276.    if (!(fileinfo = AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC)))
  277.       return FALSE;
  278.           
  279.    return TRUE;
  280. }
  281.  
  282. /* This function cleans up after DoInits. */
  283.  
  284. void CloseUp(int code, char *str) {
  285.    if (str) printf("Error: %s\n",str);
  286.    if (fileinfo) FreeMem(fileinfo,sizeof(struct FileInfoBlock));
  287.    if (namelock) UnLock(namelock);
  288.    if (DosBase) CloseLibrary((struct Library *)DosBase);
  289.    exit(code);   
  290. }
  291.  
  292. /* ====================================================================== */
  293.  
  294. /* This function finds a directory node.  It has the side effect of
  295.    setting "lastdev" to the last device in the global device list. */
  296.  
  297. struct DeviceList *AllocDirNode(char *name) {
  298.    struct DeviceList *dev, *newdev;
  299.    char *str,old[64];
  300.  
  301.   /* Let's see if the assignment has already been made... */
  302.    for (dev = (struct DeviceList *)BADDR(info->di_DevInfo); dev != NULL; 
  303.         dev = (struct DeviceList *)BADDR(dev->dl_Next)) {
  304.       lastdev = dev;
  305.       if (dev->dl_Type != DLT_DIRECTORY) continue;
  306.       b2cstr(old,dev->dl_Name);
  307.       if (!stricmp(old,name)) return dev;
  308.    }
  309.  
  310.   /* Create the new name structure */
  311.    if (!(newdev=DOSAlloc(sizeof(struct DeviceList))) || !(str=DOSAlloc(32L))) {
  312.       if (newdev) DOSFree(newdev);
  313.       return NULL;
  314.    }
  315.    newdev->dl_Type = DLT_DIRECTORY;
  316.    strcpy(str+1,name);
  317.    str[0] = strlen(name);
  318.    newdev->dl_Name = CADDR(str);
  319.    return newdev;
  320. }
  321.  
  322. /* This function does the "Assign" operation. */
  323.  
  324. BOOL Assign(char *name, char *path) {
  325.    BPTR block;
  326.    struct DeviceList *newdev;
  327.  
  328.   /* Let's verify that the path object is really there.  If not, try to make
  329.      the thing. */
  330.    if (!(block = Lock(path,SHARED_LOCK))) {
  331.       if (!(block = CreateDir(path))) return FALSE;
  332.       UnLock(block);
  333.       if (!(block = Lock(path,SHARED_LOCK))) return FALSE;
  334.    }
  335.  
  336.   /* Get a node for this assignment. */
  337.    Forbid();
  338.    newdev = AllocDirNode(name);
  339.  
  340.   /* Make the assignment */
  341.    if (newdev->dl_Lock) {
  342.       Permit();
  343.       UnLock(newdev->dl_Lock);
  344.       newdev->dl_Lock = block;
  345.       newdev->dl_Task = ((struct FileLock *)BADDR(block))->fl_Task;
  346.       return TRUE;
  347.    }
  348.    newdev->dl_Lock = block;
  349.    newdev->dl_Task = ((struct FileLock *)BADDR(block))->fl_Task;
  350.  
  351.    /* Now link it into the device list. */
  352.    newdev->dl_Next = lastdev->dl_Next;
  353.    lastdev->dl_Next = CADDR(newdev);
  354.    Permit();
  355.    return TRUE;
  356. }
  357.  
  358. /* This list takes in a node list, and performs assignments for all non-primary
  359.    nodes in the list, as long as "inhibit" is FALSE. */
  360.  
  361. void AssignList(struct List *lst, int level, BOOL inhibit) {
  362.    struct Node *n;
  363.    struct NameNode *nn;
  364.    
  365.    for (n = lst->lh_Head; n->ln_Succ; n = n->ln_Succ) {
  366.       nn = (struct NameNode *)n;
  367.       if (nn->path) {
  368.          if (!inhibit) Assign(nn->node.ln_Name,nn->path);
  369.          if (verbose || inhibit)
  370.      printf("%*s%-20s%*s%s\2330m\n",level+1,"\23333m",nn->node.ln_Name,
  371.                                        14-level,"\23332m",nn->path);
  372.       }
  373.       if (nn->children.lh_Head->ln_Succ) 
  374.          AssignList(&nn->children,level+2,inhibit);
  375.    }
  376. }
  377.  
  378. /* ====================================================================== */
  379.  
  380. void main(int argc, char *argv[]) {
  381.    char path[256];
  382.    long i;
  383.    struct NameNode *nn;
  384.    struct DeviceList *dev;
  385.    BOOL die = FALSE;
  386.  
  387.    if (!DoInits()) CloseUp(5,NULL);
  388.  
  389.   /* Check the command line. */
  390.    for (i = 1; i < argc; ++i)
  391.    {
  392.       switch (toupper(argv[i][0]))
  393.       {
  394.          case 'S':
  395.             Assign("SYS",argv[++i]);
  396.             break;
  397.          case 'V':
  398.             verbose = TRUE;
  399.             break;
  400.          case 'T':
  401.             test = TRUE;
  402.             verbose = TRUE;
  403.             break;
  404.          case 'O':
  405.             oldBehavior = TRUE;
  406.             break;
  407.          case '?':
  408.         die = TRUE;
  409.         break;
  410.       }
  411.    }
  412.  
  413.    if (die)
  414.    {
  415.     Hello();
  416.     printf("Usage: %s [VERBOSE] [TEST] [OLD] [SYSTEM drive]\n", 
  417.            argv[0]);
  418.         CloseUp(0,NULL);
  419.    }
  420.  
  421.    if (verbose)
  422.     Hello();
  423.       
  424.   /* Let's build the internal device list.  We know this list is going to be
  425.      a flat list; everything is primary, and thus hung from the root list. */
  426.    NewList(&Names);
  427.    Forbid();
  428.    for (dev = (struct DeviceList *)BADDR(info->di_DevInfo); dev != NULL; 
  429.         dev = (struct DeviceList *)BADDR(dev->dl_Next)) {
  430.       if (oldBehavior)
  431.       {
  432.           if (!(nn = MakeNode(strupr(b2cstr(path,dev->dl_Name)),NULL)))
  433.               continue;
  434.       }
  435.       else
  436.       {
  437.           if (!(nn = MakeNode(b2cstr(path,dev->dl_Name),NULL)))
  438.               continue;
  439.       }
  440.       AddHead(&Names,(struct Node *)nn);
  441.    }
  442.    Permit();
  443.    
  444.   /* I need to build the "lostnodes" node.  In order to avoid name collisions,
  445.      I make the name of this node '\0'.  We never need to search for it by
  446.      name... */
  447.  
  448.    AddTail(&Names,(struct Node *)(lostnodes = MakeNode("\0",NULL)));
  449.     
  450.   /* Here I build the list of required assignments by walking through the
  451.      SYS:Names directory, and reading each file. */
  452.   
  453.     if ((namelock = Lock(NameDir(),SHARED_LOCK))) {
  454.       Examine(namelock,fileinfo);
  455.       while (ExNext(namelock,fileinfo) || IoErr() != ERROR_NO_MORE_ENTRIES) {
  456.          if (fileinfo->fib_DirEntryType > 0) continue;
  457.          strcat(strcat(strcpy(path,NameDir()),"/"),fileinfo->fib_FileName);
  458.          AddFIB(fileinfo,path);
  459.       }
  460.    }
  461.  
  462.   /* Now I've got everything; let's see what's actually here. */
  463.   
  464.    Remove((struct Node *)lostnodes);
  465.  
  466.    if (verbose) printf("Assigned Names:\n");
  467.    AssignList(&Names,1,test);
  468.    if (lostnodes->children.lh_Head->ln_Succ) {
  469.       if (verbose) printf("\n");
  470.       printf("Warning: Can't Resolve Names:\n");
  471.       AssignList(&lostnodes->children,1,TRUE);
  472.    }
  473.    CloseUp(0,NULL);
  474. }
  475.